package com.irdstudio.efp.esb.service.client.impl;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.PascalNameFilter;
import com.irdstudio.basic.framework.core.exception.ESBException;
import com.irdstudio.efp.esb.common.client.req.EsbReqServiceBean;
import com.irdstudio.efp.esb.common.client.resp.EsbRespRetInfBean;
import com.irdstudio.efp.esb.common.client.resp.EsbRespServiceBean;
import com.irdstudio.efp.esb.common.client.resp.EsbRespSysHeadBean;
import com.irdstudio.efp.esb.service.client.*;
import com.irdstudio.efp.esb.service.client.impl.ESBClient;
import com.irdstudio.efp.esb.service.client.impl.ESBClientImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.*;

import java.util.*;

/**
 * 需求编号:2019D08--
 * 问题编号:
 * 开发人员: caoxin
 * 创建日期:2019/9/26
 * 功能描述:
 * 修改日期:2019/9/26
 * 修改描述:
 */
public class ReferenceESBClientImpl implements ESBClient {
    /** ESB请求报文体 **/
    private final Object sendBodyBean;
    /** 接口交易代码 **/
    private final String tradeNo;
    /** 服务场景 **/
    private final String scene;
    /** ESBBaseBean **/
    private final EsbBaseBean esbBaseBean;
    /** RestTemplate **/
    private final HttpClientFactory httpClientFactory;
    /** ESB配置，提供url等配置信息 **/
    private final ESBConfig config;
    /** ESB请求Bean的创建器 **/
    private final REsbBeanCreator creator;

    private static final Logger log = LoggerFactory.getLogger(ESBClientImpl.class);

    public ReferenceESBClientImpl(ESBRequestBuilder.Builder builder) {
        this.sendBodyBean = Objects.requireNonNull(builder.getToSend());
        this.tradeNo = Objects.requireNonNull(builder.getTradeNo());
        this.scene = Objects.requireNonNull(builder.getScene());
        this.httpClientFactory = Objects.requireNonNull(builder.getFactory());
        this.config = Objects.requireNonNull(builder.getConfig());
        this.creator = Objects.requireNonNull(builder.getESBBeanFactory());
        this.esbBaseBean = Objects.requireNonNull(builder.getEsbBaseBean());
    }


    @Override
    public EsbRespServiceBean sendAndReceive() throws ESBException {
        try {
            EsbReqServiceBean clientBean = creator.create(tradeNo, scene, esbBaseBean, sendBodyBean);
            String recvJson = doSend(clientBean, config.getUrl());
            log.info("接收到Json：" + recvJson);
            EsbRespServiceBean recvBean = JSONObject.parseObject(recvJson, EsbRespServiceBean.class);
            List<EsbRespRetInfBean> array = Optional.ofNullable(recvBean.getSysHead())
                    .map(EsbRespSysHeadBean::getRetInfArry)
                    .orElseGet(ArrayList::new);
            if ( array
                    .stream()
                    // 有些接口在系统头的返回数组中没有RetCd字段，过滤掉为空的  by zhoucs1 时间：2019/06/20
                    .map(EsbRespRetInfBean::getRetCd).filter(Objects::nonNull)
                    .anyMatch(i -> i.startsWith("ESB"))
            ) {
                String errorMsg = "ESB接口异常, 异常信息数组：" + array;
                throw new ESBException(errorMsg);
            }
            return recvBean;
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new ESBException(e);
        }
    }

    /**----------------------------------------------------**/
    /**                   private methods                  **/
    /**----------------------------------------------------**/

    private String doSend(EsbReqServiceBean clientBean, String url) {
        // 将发送的bean转换为json
        String sendJson = JSONObject.toJSONString(clientBean,new PascalNameFilter());
        log.info("发送Json: " + sendJson + ",ESB目标url:" + url);
        HttpHeaders headers = new HttpHeaders();
        headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
        HttpEntity<String> entity = new HttpEntity<String>(sendJson, headers);
        ResponseEntity<String> recvEntity =
                httpClientFactory.getClient()
                        .exchange(url, HttpMethod.POST, entity, String.class, new Object[]{});
        return recvEntity.getBody();
    }
}
